package com.cskaoyan.javase.oop3.abstract1.basic2;

/**
 * @description: 抽象类的成员特点和子类特点
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 抽象类的成员
 * - 成员变量
 * 抽象类的成员变量和普通类一模一样，没有任何区别
 * 普通类能够定义的成员变量，抽象类都能定义
 * - 成员方法
 * 1，能够定义普通成员方法
 *  一般来说，抽象类当中定义普通成员方法，是作为一个默认实现提供给子类，子类可以自由选择是直接继承还是重写
 *  注意：在一些比较极端的程序员看来，抽象类都是一个抽象的概念了，不应该能够做具体的事情，不应该有方法实现，而是全部抽象方法
 *  我建议：白猫黑猫抓住老鼠就好，所以说实现需求最重要，不要去管这些乱七八槽的定义的问题
 *  如果有一个方法写实现是比较好的，省事的，那你肯定要写
 *
 * 2，能够定义普通静态方法
 *  但是一般很少这么做，但是如果希望有一个静态方法被子类继承，还是可以这么做的，语法允许
 *  一切为了实现需求
 *  静态方法虽然能继承，但是不能被重写
 *
 * 3,定义抽象方法
 * 抽象类中可以定义抽象方法，一旦定义抽象方法，那么必须在普通子类中实现全部的抽象方法，除非该子类也是抽象的
 *
 * 4，抽象类中完全可以没有抽象方法
 * 抽象类无法实例化，所以有些二流程序员会直接把一个普通类声明为抽象，让外界无法创建对象
 * 不要这么做，如果需求是让外界无法创建对象，直接私有化构造方法即可
 * 抽象类是一个设计上的概念，不是纯粹为了不让创建对象
 * 所以一般情况下，抽象类中都要有抽象方法，否则该抽象类意义不大
 *
 * - 构造方法
 * 思考：抽象类有没有构造方法？
 * 抽象类是无法实例化，但是抽象类中有普通成员变量
 * 如果它没有构造方法，那么子类怎么才能给这些普通成员变量赋值呢？
 * 子类对象的初始化：super(参数) 给父类成员变量赋值
 * 所以抽象类也必须有构造方法
 * 虽然抽象类自己没法用，但是可以给子类用
 * 一句话：Java当中所有的类都有构造方法，包括抽象类
 *
 *
 * >  抽象类的子类的特点：
 * - 抽象类的子类可以是抽象类，也可以是具体类
 * - 只有当子类重写了，所有的继承自抽象类的方法，该子类才能被定义为具体类
 * - 反之，若任一抽象方法没有被重写，该类都必须定义为抽象类
 * 一个类中若想有抽象方法，必须是抽象类
 *
 */
public class Demo {
    public static void main(String[] args) {
      /*  Person p = new Student();
        p.test();

        Person.testStatic();*/

        Student s = new Student(10);
        System.out.println(s.a);
    }
}
abstract class Person {
    //成员变量
    //从普通成员变量到静态 常量
    int a;
    //int b = 10;
    static int c;
    static final int D = 10;

    public Person(int a) {
        this.a = a;
    }

    public Person() {
    }

    //定义普通成员方法
    //抽象类虽然不能实例化，但是它有子类，子类可以继承这个普通成员方法
    public void test(){
        System.out.println("abstract test");
    }
    //定义普通的静态方法
    public static void testStatic(){
        System.out.println("abstract static");
    }

    //定义抽象方法
    public abstract void testAbstract();
    //public abstract void testAbstract2();

    //抽象方法可以是私有的吗？private
    //抽象方法是必须要被子类重写的
    //私有方法无法重写。所以不能
    //Illegal combination of modifiers: 'abstract' and 'private' 非法的标识符组合
    //private abstract void testPrivate();
    //抽象方法写出来 天生就是为了给子类重写的，不能用private修饰，如果不是特殊情况，该方法一定是public修饰
    //鼓励子类去重写

    //抽象方法可以是静态的吗？static
    //1，静态方法同类类名调用，一个没有方法体的抽象方法别人咋调？
    //2，静态方法可以被继承 但是无法重写
    //Illegal combination of modifiers: 'abstract' and 'static'
    //public static abstract void testStatic();

    //抽象方法可以用final修饰吗？
    //因为final方法无法被重写，这里也不行
    //Illegal combination of modifiers: 'final' and 'abstract'
    //public final abstract void testStatic();

}

 class Student extends Person {
     @Override
     public void testAbstract() {

     }
     //@Override Method does not override method from its superclass
    //public static void testStatic(){
    //    System.out.println("abstract static");
    //}

    //Class 'Student' must either be declared abstract or implement abstract method 'testAbstract()' in 'Person'


     public Student(int a) {
         super(a);//调用父类构造方法 给父类成员赋值
     }

     public Student() {
     }
 }

class Teacher extends Person {
    @Override
    public void testAbstract() {
        System.out.println("Teacher implement abstract method");
    }
}
